#include <stdafx.h>
#include "UserDrag.h"

Lit::Vec2 UserDrag::mouseWidgetRatio( QPoint localpos, QRect geometry )
{ 
	RectType geo = geometry; //mOgreWidget->geometry();
	PointType pos = localpos;// mapTo( mOgreWidget, evt->pos() );
	return FloatPointType((float)pos.x() / (float)geometry.width(), (float)pos.y() / (float)geometry.height());
}

UserDrag::UserDrag( QWidget*widget, UserDrag::DragFlags flags, CallbackType call_back )
{ 
	mCallback = call_back;
	mFlags = flags; 
	mDrag = false;
	mButton = UDB_NONE;
	// if in frame delta mode and forgot to drop rubber band, clears rubber band
	if( mFlags.test(UDF_FRAME_DELTA) && !mFlags.test(UDF_NO_RUBBER_BAND) ) mFlags.add( UDF_NO_RUBBER_BAND );
	if( !mFlags.test(UDF_NO_RUBBER_BAND) ) 
		mBand = new RubberBandType(QRubberBand::Rectangle, widget); 
}
UserDrag::UserDrag( const UserDrag& rhs ){ mCallback=rhs.mCallback; mButton=rhs.mButton; mDrag=rhs.mDrag; mDragStart=rhs.mDragStart; mDragEnd=rhs.mDragEnd; mBand=rhs.mBand; mFlags=rhs.mFlags; }
UserDrag::~UserDrag(){ 
	if( hasRubberBand() && mBand ) delete mBand, mBand = NULL; 
}

bool UserDrag::draggedAtLeast( const SizeType& sz ) const{ return (*this) >= sz; }
bool UserDrag::isFrameDelta() const{ return mFlags & UDF_FRAME_DELTA; }
bool UserDrag::isButtonReleaseDelta() const{ return mFlags & UDF_BUTTON_RELEASE_DELTA; }
UserDrag& UserDrag::operator=( const UserDrag& rhs ){ if( mBand ) delete mBand, mBand = NULL; mCallback=rhs.mCallback; mButton=rhs.mButton; mDrag=rhs.mDrag; mDragStart=rhs.mDragStart; mDragEnd=rhs.mDragEnd; mBand=rhs.mBand; mFlags=rhs.mFlags; return *this; }

UserDrag::ButtonType				UserDrag::button()					const{ return mButton; }
bool					UserDrag::isDragging()				const{ return mDrag; }
	
bool					UserDrag::hasRubberBand()				const{ return (!(mFlags & UDF_NO_RUBBER_BAND)); }
const UserDrag::DragFlags	&		UserDrag::flags()						const{ return mFlags; }
UserDrag::DragFlags	&			UserDrag::flags()							{ return mFlags; }

const UserDrag::PointType&		UserDrag::start()						const{ return mDragStart; }
const UserDrag::PointType&		UserDrag::end()						const{ return mDragEnd; }

UserDrag::RubberBandType*			UserDrag::rubberBand()					{ return mBand; }
const UserDrag::RubberBandType*	UserDrag::rubberBand()				const{ return mBand; }

UserDrag::SizeType				UserDrag::dragSize()					const{ return SizeType( dragRect().size() ); }
UserDrag::RectType				UserDrag::dragRect()					const{ return RectType( mDragStart, mDragEnd ); }
UserDrag::PointType				UserDrag::delta()						const{ return PointType(mDragEnd-mDragStart); }
UserDrag::FloatPointType		UserDrag::deltaFactor( float factor ) const{	return FloatPointType( ((float)delta().x())*factor, ((float)delta().y())*factor ); }

bool UserDrag::operator == ( const UserDrag& rhs ) const{ return mDragStart == rhs.mDragStart && mDragEnd == rhs.mDragEnd; }
bool UserDrag::operator != ( const UserDrag& rhs ) const{ return mDragStart != rhs.mDragStart || mDragEnd != rhs.mDragEnd; }
bool UserDrag::operator > ( const UserDrag& rhs ) const{ return dragSize().width() > rhs.dragSize().width() && dragSize().height() > rhs.dragSize().height(); }
bool UserDrag::operator < ( const UserDrag& rhs ) const{ return dragSize().width() < rhs.dragSize().width() && dragSize().height() < rhs.dragSize().height(); }
bool UserDrag::operator >= ( const UserDrag& rhs ) const{ return dragSize().width() >= rhs.dragSize().width() && dragSize().height() >= rhs.dragSize().height(); }
bool UserDrag::operator <= ( const UserDrag& rhs ) const{ return dragSize().width() <= rhs.dragSize().width() && dragSize().height() <= rhs.dragSize().height(); }
bool UserDrag::operator > ( const SizeType& rhs ) const{ return dragSize().width() > rhs.width() && dragSize().height() > rhs.height(); }
bool UserDrag::operator < ( const SizeType& rhs ) const{ return dragSize().width() < rhs.width() && dragSize().height() < rhs.height(); }
bool UserDrag::operator >= ( const SizeType& rhs ) const{ return dragSize().width() >= rhs.width() && dragSize().height() >= rhs.height(); }
bool UserDrag::operator <= ( const SizeType& rhs ) const{ return dragSize().width() <= rhs.width() && dragSize().height() <= rhs.height(); }

void UserDrag::initDrag( const UserDrag::PointType& start_point, UserDrag::ButtonType btn )
{
	mDragStart = start_point;
	mDragEnd = mDragStart;
	mDrag = true;
	mButton = btn;
	// sets up rubber band
	if( hasRubberBand() )
	{
		mBand->setGeometry(QRect(mDragStart, QSize()));
		mBand->show();
	}

	if( mCallback ) mCallback( UDE_INIT, this );
}

void UserDrag::updateDrag( const UserDrag::PointType& curr_pos, bool force_update )
{
	// if wrong drag button, 
	// or not in drag mode, 
	// return
	if( !mDrag ){
		if( !force_update ) return;
	}
	if( isFrameDelta() )
	{
		// drag delta updated each frame
		mDragStart = mDragEnd;
		mDragEnd = curr_pos;
	}
	else if( isButtonReleaseDelta() )
	{ 
		// drag delta updated after button release
		mDragEnd = curr_pos;
	}
	if( mCallback )
		mCallback( UDE_UPDATE, this );
	// updates rubber band if has rubber band
	if( hasRubberBand() )
		mBand->setGeometry(QRect(mDragStart, mDragEnd).normalized());
}

void UserDrag::closeDrag( const UserDrag::PointType& end_pos )
{
	// if wrong drag button, 
	// or not in drag mode, 
	// return
	if( !mDrag ) return;
	// hides rubber band
	if( hasRubberBand() )
		mBand->hide();
	if( mCallback )
		mCallback( UDE_STOP, this );
	// ends drag
	mDrag = false;
	mDragEnd = end_pos;
}